﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Money.Interface
{
    // TODO because we create a new list on updates anything that uses this list direct cannot access the information
    // TODO we should update this feature so that we can prioritise the entries and also terminate on an entry (i.e. like rbs imports)

    public partial class DescriptionMatchForm : Form
    {
        private enum State
        {
            Add,
            Edit,
            View,
            Saved,
            Cancel
        }

        State _state = State.View;

        List<DescriptionMatch> _descriptionTidyList = new List<DescriptionMatch>();
        DescriptionMatch _editingMatch = null;

        private int _lastSelectedRow = -1;

        public DescriptionMatchForm(List<DescriptionMatch> nameList)
        {
            InitializeComponent();

            _grid.AutoGenerateColumns = false;

            _descriptionTidyList = nameList;

            SetGridDataSource();

            _actionButton.Enabled = false;
        }

        private void PopulateEditingControls(DescriptionMatch match)
        {
            _regularExpression.Text = match.RegularExpression;
            _description.Text = match.Description;
            _priority.Text = match.Priority.ToString();
            _terminate.Checked = match.Terminate;
        }

        private void SetGridDataSource()
        {
            var dataSource = from match in _descriptionTidyList orderby match.Priority descending select match;

            _grid.DataSource = null;
            _grid.DataSource = dataSource.ToList();
        }

        private void _actionButton_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(_regularExpression.Text) && !string.IsNullOrEmpty(_description.Text))
            {
                DescriptionMatch match = null;

                switch (_state)
                {
                    case State.Edit:
                        match = _editingMatch;
                        break;

                    case State.Add:
                        match = new DescriptionMatch();
                        _descriptionTidyList.Add(match);
                        break;
                }

                try
                {
                    match.Priority = Convert.ToInt32(_priority.Text);
                }
                catch
                {
                    match.Priority = 100;
                }

                match.Terminate = _terminate.Checked;
                match.RegularExpression = _regularExpression.Text;
                match.Description = _description.Text;

                ClearControls();

                SetGridDataSource();

                _state = State.View;
            }
        }

        private void _clearButton_Click(object sender, EventArgs e)
        {
            ClearControls();
            EnableControls(true);
            _state = State.Add;
            _grid.ClearSelection();
        }


        private void ClearControls()
        {
            _regularExpression.Text = "";
            _priority.Text = "";
            _description.Text = "";
            _terminate.Text = "false";
            _editingMatch = null;
            _lastSelectedRow = -1;
        }

        private void _grid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            DescriptionMatch nm = (DescriptionMatch)_grid.Rows[e.RowIndex].DataBoundItem;

            _descriptionTidyList.Remove(nm);
            _description.Text = nm.Description;
            _regularExpression.Text = nm.RegularExpression;

            _grid.DataSource = null;
            _grid.DataSource = _descriptionTidyList;
        }

        private void _grid_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridView grid = sender as DataGridView;

            if (grid == null)
            {
                return;
            }

            if (e.RowIndex < 0)
            {
                return;
            }

            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    break;

                case System.Windows.Forms.MouseButtons.Right:
                    if (grid.SelectedRows.Count > 1)
                    {
                        deleteEntriesMenuItem.Text = "Delete Entries";
                    }
                    else
                    {
                        deleteEntriesMenuItem.Text = "Delete Entry";
                    }
                    contextMenu.Show(System.Windows.Forms.Cursor.Position);
                    break;
            }
        }

        private void deleteEntriesMenuItem_Click(object sender, EventArgs e)
        {
            DataGridView grid = _grid;

            if (grid != null)
            {
                if (grid.SelectedRows.Count > 0)
                {
                    DialogResult result = MessageBox.Show("Do you want to delete " + grid.SelectedRows.Count + " entries?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);

                    if (result == System.Windows.Forms.DialogResult.Yes)
                    {
                        foreach (DataGridViewRow row in grid.SelectedRows)
                        {
                            DescriptionMatch match = row.DataBoundItem as DescriptionMatch;

                            if (match != null)
                            {
                                _descriptionTidyList.Remove(match);
                            }
                        }

                        ClearControls();
                        SetGridDataSource();
                    }
                }
            }
        }

        private void _descriptionGrid_SelectionChanged(object sender, EventArgs e)
        {
            // if last row is equal to -2 then this is a special case where we do not want to do anything as we are mid-operation
            if (_lastSelectedRow == -2)
            {
                return;
            }

            // if we have no selection then we can add a record
            if (_grid.SelectedRows.Count == 0)
            {
                EnableControls(true);
                ClearControls();
                _state = State.Add;
                _lastSelectedRow = -1;
            }
            // if we have one selection then we can change an entry
            else if (_grid.SelectedRows.Count == 1)
            {
                if (_lastSelectedRow == _grid.SelectedRows[0].Index)
                {
                    return;
                }

                DescriptionMatch match = _grid.SelectedRows[0].DataBoundItem as DescriptionMatch;

                if (match != null)
                {
                    // TODO we need to prevent changing selected item if we have made edits
                    // HACK at least give some warning that we may lose edits
                    if (_editingMatch != null && _editingMatch != match && EditChanged(_editingMatch))
                    {
                        if (MessageBox.Show("The current edit has not been completed, do you want to cancel this edit?", "Cancel Current Edit!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.No)
                        {
                            int restoreRow = _lastSelectedRow;
                            _lastSelectedRow = -2;
                            _grid.SelectedRows[0].Selected = false;
                            _grid.Rows[restoreRow].Selected = true;
                            _lastSelectedRow = restoreRow;
                            return;
                        }
                    }
                    PopulateEditingControls(match);

                    EnableControls(true);
                    _state = State.Edit;
                    _editingMatch = match;
                    _lastSelectedRow = _grid.SelectedRows[0].Index;
                }
                else
                {
                    _lastSelectedRow = -1;
                    EnableControls(true);
                    ClearControls();
                    _state = State.Add;
                }
            }
            // if we have more than one then we cannot od anything other than delete so disable edit controls
            else
            {
                EnableControls(false);

                ClearControls();
                _state = State.View;
            }

            ConfigureActionButton();
        }

        /// <summary>
        /// This method is called when any data entry object is edited on the screen. Check if we should change control operation if we have a changed value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ValidAfterEdit(object sender, EventArgs e)
        {
            ConfigureActionButton();
        }

        private void ConfigureActionButton()
        {
            switch (_state)
            {
                case State.Add:
                    _actionButton.Text = _state.ToString();
                    if (!string.IsNullOrWhiteSpace(_regularExpression.Text) && !string.IsNullOrEmpty(_description.Text))
                    {
                        _actionButton.Enabled = true;
                    }
                    else
                    {
                        _actionButton.Enabled = false;
                    }
                    break;

                case State.Edit:
                    _actionButton.Text = _state.ToString();

                    if (!string.IsNullOrWhiteSpace(_regularExpression.Text) && !string.IsNullOrWhiteSpace(_description.Text) && EditChanged(_editingMatch))
                    {
                        _actionButton.Enabled = true;
                    }
                    else
                    {
                        _actionButton.Enabled = false;
                    }
                    break;

                default:
                    _actionButton.Enabled = false;
                    break;
            }
        }

        private bool EditChanged(DescriptionMatch match)
        {
            bool changed = false;

            // TODO this needs expanded so that any change is detected
            if (!_regularExpression.Text.Equals(match.RegularExpression) || _terminate.Checked != match.Terminate || !_priority.Text.Equals(match.Priority.ToString()) || !_description.Text.Equals(match.Description))
            {
                changed = true;
            }

            return changed;
        }

        private void EnableControls(bool state)
        {
            _regularExpression.Enabled = state;
            _description.Enabled = state;
            _priority.Enabled = state;
            _terminate.Enabled = state;
        }
    }
}
